﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Obsidian.GameObjects;

namespace Obsidian.Components
{
    public enum SendMessageOptions
	{
        RequireReceiver,
        DontRequireReceiver,
	}


    /// <summary>
    /// Base class for everything attached to GameObjects.
    /// </summary>
    public class Component
    {
        /// <summary>
        /// The name of the object.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// The Transform attached to this GameObject (null if there is none attached).
        /// </summary>
        public Transform Transform { get { return GameObject.Transform; } set { GameObject.Transform = value; } }

        /// <summary>
        /// The Renderer attached to this GameObject (null if there is none attached).
        /// </summary>
        public Renderer Renderer { get { return GameObject.Renderer; } set { GameObject.Renderer = value; } }

        /// <summary>
        /// The Camera attached to this GameObject (null if there is none attached).
        /// </summary>
        public Camera Camera { get { return GameObject.Camera; } set { GameObject.Camera = value; } }

        /// <summary>
        /// The game object this component is attached to. A component is always attached to a game object.
        /// </summary>
        public GameObject GameObject { get; set; }

        /// <summary>
        /// The tag of this game object.
        /// </summary>
        public string Tag { get { return GameObject.Tag; } set { GameObject.Tag = value; } }

        /// <summary>
        /// Constructor for components.
        /// </summary>
        public Component(string name = "Undefined")
        {
            Name = name;
        }

        /// <summary>
        /// Returns the component of Type type if the game object has one attached, null if it doesn't.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public Component GetComponent(Type type)
        {
            foreach (var component in GameObject.Components)
            {
                if (component.GetType() == type)
                {
                    return component;
                }
            }

            // non found 
            return null;
        }

        /// <summary>
        /// Returns the component with name type if the game object has one attached, null if it doesn't.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Component GetComponent(string name)
        {
            foreach (var component in GameObject.Components)
            {
                if (component.Name == name)
                {
                    return component;
                }
            }

            // non found 
            return null;
        }

        /// <summary>
        /// Returns the component of Type type if the game object has one attached, null if it doesn't.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public Component GetComponent<T>()
        {
            foreach (var component in GameObject.Components)
            {
                if (component.GetType() == typeof(T))
                {
                    return component;
                }
            }

            // non found 
            return null;
        }

        /// <summary>
        /// Returns all components of Type type in the GameObject.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public Component[] GetComponents(Type type)
        {
            List<Component> components = new List<Component>();

            foreach (var component in GameObject.Components)
            {
                if (component.GetType() == type)
                {
                    components.Add(component);
                }
            }
            return components.ToArray();
        }

        /// <summary>
        /// Returns all components of Type type in the GameObject.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public Component[] GetComponents<T>()
        {
            List<Component> components = new List<Component>();

            foreach (var component in GameObject.Components)
            {
                if (component.GetType() == typeof(T))
                {
                    components.Add(component);
                }
            }
            return components.ToArray();
        }

        /// <summary>
        /// Is this game object tagged tag?
        /// </summary>
        /// <param name="tag">Tag to compare.</param>
        /// <returns></returns>
        public bool CompareTag(string tag)
        {
            return (tag == GameObject.Tag);
        }
       
        // Are messages really needed?
        /// <summary>
        /// Calls the method named methodName on every Script in this game object.
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="value"></param>
        /// <param name="options"></param>
        public void SendMessage(string methodName, object value = null, SendMessageOptions options = SendMessageOptions.RequireReceiver)
        {

        }

        /// <summary>
        /// Calls the method named methodName on every Script in this game object or any of its children.
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="value"></param>
        /// <param name="options"></param>
        public void BroadcastMessage(string methodName, object value = null, SendMessageOptions options = SendMessageOptions.RequireReceiver)
        {

        }
    }
}
